const { ccclass, property, executeInEditMode, disallowMultiple, playOnFocus } = cc._decorator;

enum Time {
    none = 0,
    onLoad = 1,
    start = 2,
    onEnable = 3
}

const timeEnum = cc.Enum(Time);

@ccclass
@playOnFocus
@executeInEditMode
@disallowMultiple
export default abstract class basePlay extends cc.Component {
    protected _needPreview: boolean = true;
    protected _preview: boolean = false;
    @property({
        tooltip: CC_DEV && '是否开启预览',
        visible(this: basePlay) {
            return this._needPreview;
        }
    })
    get preview() { return this._preview; }
    set preview(value) {
        if (CC_EDITOR && this.node.activeInHierarchy && this.enabled) {
            this._preview = value;
            if (value) {
                this.isPausing() ? this.resume() : this._play(-1);
            } else {
                this.pause();
            }
        }
    }

    @property({
        type: timeEnum
    })
    time: Time = Time.none;

    @property
    protected _playDelay: number = 0;
    @property({
        visible(this: basePlay) {
            return this.time !== Time.none;
        }
    })
    get playDelay(): number { return this._playDelay }
    set playDelay(value) {
        if (value < 0) value = 0;
        this._playDelay = value;
    }

    @property
    loop: boolean = false;

    @property
    protected _loopInterval: number = 0;
    @property({
        visible(this: basePlay) {
            return this.time !== Time.none && this.loop;
        }
    })
    get loopInterval(): number { return this.loop ? this._loopInterval : 0; }
    set loopInterval(value) {
        if (value < 0) value = 0;
        this._loopInterval = value;
    }

    // 等待计时
    private _delayDt = 0;
    // 循环次数
    private _loopCount = 0;

    // 正在暂停
    private _pausing = false;
    // 正在播放
    private _playing = false;
    // 每一帧时长计时
    private _frameDt = 0;
    // 每一帧时长
    private _frameTime = 0;

    // 虚函数，返回值代表是否播放成功
    protected abstract _play(loopCount: number): boolean;
    // 可重写
    protected _beforeRender(dt?: number): any { }
    // 虚函数，返回值会传给_afterRender
    protected abstract _render(dt?: number): boolean;
    // 当返回false时代表，play完一次了
    protected _afterRender(data: boolean, dt?: number): boolean {
        return data;
    }

    /**
     * 【编辑器】所在节点失去焦点
     */
    protected onLostFocusInEditor = CC_EDITOR && function () {
        if (this._needPreview) {
            this._preview = false;
            this.pause();
        }
    }

    /**
     * 基类播放
     * @param time      [每一帧时长]
     * @param loopCount [循环次数]
     * [loopCount = 0] 播放loopCount + 1次，不受loop影响
     * [loopCount < 0] 无限循环，不受loop影响
     */
    protected basePlay(frameTime: number, loopCount?: number) {
        // 不传入loopCount时，loop为真则循环，loop为假则执行一次
        if (typeof loopCount !== 'number') {
            loopCount = this.loop ? -1 : 0;
        }
        this._frameDt = frameTime;
        this._frameTime = frameTime;
        this._loopCount = Math.floor(loopCount);
        this._delayDt = 0;
        this._playing = true;
        this._pausing = false;
    }

    public stop() {
        if (!this.isPlaying()) return false;
        this._playing = false;
        this._pausing = false;
        return true;
    }

    public pause() {
        if (!this.isPlaying() || this.isPausing()) return false;
        this._pausing = true;
        return true;
    }

    public resume() {
        if (!this.isPlaying() || !this.isPausing()) return false;
        this._pausing = false;
        return true;
    }

    public isPlaying() {
        return this._playing;
    }

    public isStopped() {
        return !this._playing;
    }

    public isPausing() {
        return this._pausing;
    }

    onLoad() {
        if (CC_EDITOR) return;
        if (this.time === Time.onLoad) {
            this._play(this.loop ? -1 : 0);
        }
    }

    start() {
        if (CC_EDITOR) return;
        if (this.time === Time.start) {
            this._play(this.loop ? -1 : 0);
        }
    }
    onEnable() {
        if (CC_EDITOR) return;
        if (this.time === Time.onEnable) {
            this._play(this.loop ? -1 : 0);
        }
    }

    update(dt: number) {
        if (CC_EDITOR && !this.preview) return;

        if (this._playing === false || this._pausing) return;

        //  等待
        if (this._delayDt < this.playDelay) {
            this._delayDt += dt;
            if (this._delayDt < this.playDelay) {
                return;
            }
        }

        // 累加dt
        if (this._frameDt < this._frameTime) {
            this._frameDt += dt;
        }

        // 进行
        if (this._frameDt >= this._frameTime) {
            this._frameDt -= this._frameTime;
            // 返回false代表结束了
            this._beforeRender(dt);
            const data = this._render(dt);
            const result = this._afterRender(data, dt);

            if (result === false) {
                if (this._loopCount > 0) {
                    --this._loopCount;
                    this._frameDt = 0;
                    this._delayDt = this.playDelay - this.loopInterval;
                } else if (this._loopCount < 0) {
                    this._frameDt = 0;
                    this._delayDt = this.playDelay - this.loopInterval;
                } else {
                    this.stop();
                }
            }
        }
    }
}
